package org.budo.support.java.concurrent.executor;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author lmw
 */
public class ExecutorUtil {
    /**
     * 在限定时间内执行一段代码并返回值
     * 
     * @param callable 被执行的代码
     * @param timeout  超时时间 MILLISECONDS
     */
    public static <T> T executeAndGet(Callable<T> callable, Integer timeout) {
        FutureTask<T> futureTask = new FutureTask<T>(callable);

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(futureTask);

        try {
            return futureTask.get(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            futureTask.cancel(true);
            throw new RuntimeException("#31 timeout=" + timeout + ", callable=" + callable, e);
        } catch (ExecutionException e) {
            futureTask.cancel(true);
            throw new RuntimeException("#34 timeout=" + timeout + ", callable=" + callable, e);
        } catch (TimeoutException e) {
            futureTask.cancel(true);
            throw new RuntimeException("#37 timeout=" + timeout + ", callable=" + callable, e);
        } finally {
            executorService.shutdown();
        }
    }

    /**
     * @param timeout 超时时间 MILLISECONDS
     */
    public static void execute(final Runnable runnable, Integer timeout) {
        executeAndGet(new Callable<Object>() {
            public Object call() throws Exception {
                runnable.run();
                return null;
            }
        }, timeout);
    }

    /**
     * 如果 executorService 为空，则在主线程中执行，返回空
     */
    public static <T> List<Future<T>> invokeAll(ExecutorService executorService, Collection<? extends Callable<T>> tasks) {
        if (null == executorService) {
            for (Callable<T> callable : tasks) {
                call(callable); // 主线程执行
            }

            return null; // TODO
        }

        try {
            return executorService.invokeAll(tasks);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T call(Callable<T> callable) {
        try {
            return callable.call();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Boolean awaitTermination(ExecutorService executorService, int timeout, TimeUnit timeUnit) {
        try {
            return executorService.awaitTermination(timeout, timeUnit);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}